package com.shw.loco.adapter;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidParameterException;

import android.content.Context;
import android.util.Log;
import android_serialport_api.SerialPort;

import com.shw.loco.util.InfoUtils;
import com.shw.loco.vo.ComBean;
import com.shw.loco.vo.ComPortInfo;

/**
 * @author HAHA
 */
public abstract class SerialHelper {
	private static final String TAG = "SerialHelper";
	private SerialPort serialPort;
	private OutputStream outputStream;
	private InputStream inputStream;
	private ReadThread readThread;
	private SendThread sendThread;
	private String port = "/dev/ttySAC3";
	private int baudRate = 57600;
	private boolean isOpen = false;
	private byte[] loopData;
	private int delay = 200;
	private int portinfo;
	private Context context;

	public Context getContext() {
		return context;
	}

	public void setContext(Context context) {
		this.context = context;
	}

	public SerialHelper(String port, int baudRate) {
		this.port = port;
		this.baudRate = baudRate;
	}

	public SerialHelper() {
		this("/dev/ttySAC3", 9600);
	}

	public SerialHelper(String port) {
		this(port, 9600);
	}

	public SerialHelper(String port, String baudRate) {
		this(port, Integer.parseInt(baudRate));
	}

	public void open() throws SecurityException, IOException,
			InvalidParameterException {
		serialPort = new SerialPort(new File(port), baudRate, 0);
		outputStream = serialPort.getOutputStream();
		inputStream = serialPort.getInputStream();
		switch (portinfo) {
		case InfoUtils.PORT232_GPS:
			readThread = new ReadThread(portinfo);
			readThread.start();
			break;
		case InfoUtils.PORT485_LOCO:
			readThread = new ReadThread(portinfo);
			readThread.start();
			sendThread = new SendThread();
			// sendThread.setSuspendFlag();
			sendThread.start();
			break;
		case InfoUtils.PORT485_RFID:
			sendThread = new SendThread();
			// sendThread.setSuspendFlag();
			sendThread.start();
			readThread = new ReadThread(portinfo);
			readThread.start();
			break;
		default:
			break;
		}

		isOpen = true;
	}

	public void close() {
		if (readThread != null){
			readThread.stop=true;
			readThread.interrupt();
		}
		if (sendThread != null){
			sendThread.stop=true;
			sendThread.interrupt();
		}
		if (serialPort != null) {
			serialPort.close();
			serialPort = null; 
		}
		isOpen = false;
	}

	private void send(byte[] outArray) {
		try {
			if (outArray != null)
				outputStream.write(outArray);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void read(int ports){
		try{
			if (inputStream == null)
				return;
			int receivedData=0;
			int size=0; 
			long revtime=0;
			byte[] buffer=new byte[1024];
			for(;(receivedData=inputStream.read())!=-1;size++){
				if(size==0)
					revtime=System.currentTimeMillis();
				buffer[size]=(byte)receivedData;
				if((System.currentTimeMillis()-revtime)>180)
					break;
			}
			if (size > 0) {
				ComPortInfo ComRecData = new ComPortInfo(port, buffer, size,
						ports);
				if (context != null)
					onDataReceived(ComRecData);
			}
		}catch(Exception es){
			Log.d("SerialHelper", "error");
		}
	}
	
	private void read(int readTime, int sleepTime, int ports) {
		try {
			if (inputStream == null)
				return;
			byte[] buffer = new byte[450];
			int size = 0;
			/*for(; inputStream.available() <= 0; wait()){
				Log.d("SerialHelper", "wait");
			}
			size = inputStream.read(buffer);*/
			while (inputStream.available() > 0) {
				try {
					Thread.sleep(readTime);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				size = inputStream.read(buffer);
			}
			if (size > 0) {
				ComPortInfo ComRecData = new ComPortInfo(port, buffer, size,
						ports);
				if (context != null)
					onDataReceived(ComRecData);
			}
			try {
				Thread.sleep(sleepTime);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

	public void sendHex(String hex) throws Exception{
		byte[] outArray = InfoUtils.HexToByteArr(hex);
		send(outArray);
	}

	public void sendTxt(String txt) {
		byte[] outArray = txt.getBytes();
		send(outArray);
	}

	private class ReadThread extends Thread {
		public boolean stop=false;
		private int portInfoR;

		public ReadThread(int portInfoR) {
			this.portInfoR = portInfoR;
		}

		@Override
		public void run() {
			super.run();
			while(!stop){
				switch (portinfo) {
				case InfoUtils.PORT232_GPS:
					read(portInfoR);
					break;
				case InfoUtils.PORT485_LOCO:
					read(portInfoR);
					break;
				case InfoUtils.PORT485_RFID:
					if(delay>100){
						read(50, delay-100, portInfoR);
					}else{
						read(10, delay, portInfoR);
					}
					
					break;
				default:
					break;
				}
				
			}
			
			/*while (!stop) {
				switch (portinfo) {
				case InfoUtils.PORT232_GPS:
					if(delay>100){
						if(delay>200){
						read(100, delay-150, portInfoR);}else{
							read(100, 0, portInfoR);
						} 
					}else{
						read(10, delay, portInfoR);
					}
					
					break;
				case InfoUtils.PORT485_LOCO:
					read(1, 100, portInfoR);
					break;
				case InfoUtils.PORT485_RFID:
					if(delay>100){
						read(50, delay-100, portInfoR);
					}else{
						read(10, delay, portInfoR);
					}
					
					break;
				default:
					break;
				}
			}*/
		}
	}

	private class SendThread extends Thread {
		public boolean stop=false;
		public boolean suspendFlag = true;// 控制线程的执行
		
		@Override
		public void run() {
			super.run();
			while (!stop) {
				/*
				 * synchronized (this) { while (suspendFlag) { try { wait(); }
				 * catch (InterruptedException e) { e.printStackTrace(); } } }
				 */
				switch (portinfo) {
				case InfoUtils.PORT232_GPS:

					break;
				case InfoUtils.PORT485_LOCO:
					// 发送中心转发数据
					if (LocoInfoQueue.locoQueVecotr.size() > 0) {//判断是否有请求中心转发数据的请求
						if (LocoInfoQueue.centerToLocoList.size() > 0) {//有中心转发的数据
							send(LocoInfoQueue.centerToLocoList.remove(0));
						}else{//没有有中心转发的数据
							String returnNoDataMode="690001E500";
							String returnNoData;
							try {
								returnNoData = returnNoDataMode+InfoUtils.CRC_16(InfoUtils.HexToByteArr(returnNoDataMode));
								send(InfoUtils.HexToByteArr(returnNoData));//反馈无数据
							} catch (Exception e) {
							}
							
						}
						LocoInfoQueue.locoQueVecotr.remove(0);//删除已用过的请求
					}
					// 发送校验错误数据
					if (LocoInfoQueue.locoErrorQue.size() > 0) {//判断是否有请求中心转发数据的请求
						if (LocoInfoQueue.locoErrorQueVecotr.size() > 0) {//有中心转发的数据
							send(LocoInfoQueue.locoErrorQueVecotr.remove(0));
						}
						LocoInfoQueue.locoErrorQue.remove(0);//删除已用过的请求
					}
					// 发送rfid计算后的数据
					if (LocoInfoQueue.locoRFIDQueVecotr.size() > 0) {//判断是否有请求RFID数据的请求
						if (LocoInfoQueue.resultToLocoVector.size() > 0) {//有RFID的数据
							if(LocoInfoQueue.resultToLocoVector.size() > 10){//如果RFID列表中数据达到10条，将把前9条清除，以确保将最新数据发给我机车
								for(int i=0;i<(LocoInfoQueue.resultToLocoVector.size()-1);i++){
									LocoInfoQueue.resultToLocoVector.remove(i);
								}
							}
							send(LocoInfoQueue.resultToLocoVector.remove(LocoInfoQueue.resultToLocoVector.size()-1));//从发送给机车的列表中取出最新数据发送给机车
						}else{//没有RFID的数据
							String returnNoDataMode="690001E300";
							String returnNoData;
							try {
								returnNoData = returnNoDataMode+InfoUtils.CRC_16(InfoUtils.HexToByteArr(returnNoDataMode));
								send(InfoUtils.HexToByteArr(returnNoData));//反馈无数据
							} catch (Exception e) {
							}
						}
						LocoInfoQueue.locoRFIDQueVecotr.remove(0);//删除已用过的请求
					}
					try {
						Thread.sleep(50);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					break;
				case InfoUtils.PORT485_RFID:
					if (context == null) {
						send(getLoopData());
						setbLoopData(null);
						try {
							setHexLoopData(InfoUtils.RFID_REQ);
						} catch (Exception e) {
						}
					} else {
						synchronized (this)
						{
						while (suspendFlag) {
							try {
								wait();
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}}
						send(getLoopData());
					}
					// read(1, 1);
					try {
						Thread.sleep(delay);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					break;
				default:
					break;
				}

			}
		}

		public void setSuspendFlag() {
			this.suspendFlag = true;
		}

		public synchronized void setResume() {
			this.suspendFlag = false;
			notify();
		}
	}

	public int getBaudRate() {
		return baudRate;
	}

	public boolean setBaudRate(int baudRate) {
		if (isOpen) {
			return false;
		} else {
			this.baudRate = baudRate;
			return true;
		}
	}

	public boolean setBaudRate(String baudRate) {
		int baud = Integer.parseInt(baudRate);
		return setBaudRate(baud);
	}

	public String getPort() {
		return port;
	}

	public boolean setPort(String port) {
		if (isOpen) {
			return false;
		} else {
			this.port = port;
			return true;
		}
	}

	public boolean isOpen() {
		return isOpen;
	}

	public byte[] getLoopData() {
		return loopData;
	}

	public void setbLoopData(byte[] loopData) {
		this.loopData = loopData;
	}

	public void setTxtLoopData(String txt) {
		this.loopData = txt.getBytes();
	}

	public void setHexLoopData(String hex) throws Exception {
		this.loopData = InfoUtils.HexToByteArr(hex);
	}

	public int getDelay() {
		return delay;
	}

	public void setDelay(int delay) {
		this.delay = delay;
	}

	public void startSend() {
		if (sendThread != null) {
			sendThread.setResume();
		}
	}

	public void stopSend() {
		if (sendThread != null) {
			sendThread.setSuspendFlag();
		}
	}

	public int getPortinfo() {
		return portinfo;
	}

	public void setPortinfo(int portinfo) {
		this.portinfo = portinfo;
	}

	protected abstract void onDataReceived(ComPortInfo comPortInfo);

	protected abstract void onDataReceived(ComBean comPortInfo);
}